package tests.ge;

import java.util.Iterator;

import tests.ge.BNFTester.ExpressionEvaluator;

import ge.Expression;
import ge.NonTerminal;
import ge.ProductionRule;
import ge.Terminal;
import ge.Symbol;
import ge.standardsymbols.StartSymbol;

import com.sun.org.apache.xpath.internal.operations.Variable;

public class GrammarTest {
	public static void main(String[] args) {
		(new GrammarTest()).doTest();
	}

	public void doTest() {

		ProductionRule startRule = new ProductionRule(StartSymbol.class,
				new Expression(new Class[] { Equation.class }));

		ProductionRule equationRule = new ProductionRule(Equation.class,
				new Expression(new Class[] { Equation.class, Operator.class,
						Equation.class }));
		equationRule.add(new Expression(new Class[] { Variable.class }));
		equationRule.add(new Expression(new Class[] { OpenParen.class,
				Equation.class, CloseParen.class }));
		equationRule.add(new Expression(new Class[] { Abs.class, OpenParen.class,
				Equation.class, CloseParen.class }));

		ProductionRule operatorRule = new ProductionRule(Operator.class,
				new Expression(new Class[] { Plus.class }));
		operatorRule.add(new Expression(new Class[] { Minus.class }));
		operatorRule.add(new Expression(new Class[] { Times.class }));

		Class<Integer> return_type = Integer.class;
		String[] parameter_names = {};
		Class<?>[] parameter_types = {};
		
		for (int i = 0; i < 5; i++) {
			Expression exp = StartSymbol.resolve(new DumbIterator());

			System.out.println(exp);
			String code = exp.createInstance().getCode();
			System.out.println(code);
			ExpressionEvaluator ee = new ExpressionEvaluator(code,
					return_type, parameter_names, parameter_types);
			System.out.println("Evaluates to:"
					+ ee.execute(new Object[] {}));
			System.out.println("\n");
		}
	}

	public static class Operator extends NonTerminal {
	}

	public static class Equation extends NonTerminal {
	}

	public static class Plus extends Terminal {
		@Override
		public String getCode() {
			return " + ";
		}
	}

	public static class Times extends Terminal {
		@Override
		public String getCode() {
			return " * ";
		}
	}

	public static class Divide extends NonTerminal {
		@Override
		public String getCode() {
			return " (  ";
		}
	}
	
	public static class Abs extends Terminal {
		public String getCode() {
			return " Math.abs";
		}
	}

	public static class OpenParen extends Terminal {
		@Override
		public String getCode() {
			return " ( ";
		}
	}

	public static class CloseParen extends Terminal {
		@Override
		public String getCode() {
			return " ) ";
		}
	}

	public static class Minus extends Terminal {
		@Override
		public String getCode() {
			return " - ";
		}
	}

	public static class Variable extends Terminal {
		private int _value = 0;

		public Variable() {
			_value = (int) (Math.random() * 10);
		}

		@Override
		public String getCode() {
			return Integer.toString(getIndex());
		}

	}

	public static class DumbIterator implements Iterator<Integer> {
		private int index = 0;

		@Override
		public boolean hasNext() {
			return true;
		}

		@Override
		public Integer next() {
			return (int) (Math.random() * 10);
		}

		@Override
		public void remove() {
			// do nothing
		}

	}

}
